class Cardutil {
  static final int CARD_TYPE_WAN = 0;
  static final int CARD_TYPE_TIAO = 1;
  static final int CARD_TYPE_TONG = 2;

  static List huCards(List<int> cardList) {
    List<int> huCard = [];
    if (cardList.length % 3 == 2) {
      return huCard;
    }
    for (int cardId = 1; cardId <= 27; cardId++) {
      List<int> temp = List.from(cardList);
      temp.add(cardId);
      if (checkUserHu(temp)) {
        huCard.add(cardId);
      }
    }
    return huCard;
  }

  static List<int> checkUserCallCard(List<int> userCards) {
    List<int> needExportCardResult = [];
    for (int i = 0, j = userCards.length; i < j; i++) {
      List<int> tempCards = List.from(userCards);
      int cardInfo = tempCards[i];
      removeCard(tempCards, cardInfo);
      List<int> huCards = checkUserHuCard(tempCards);
      if (null != huCards &&
          huCards.length > 0 &&
          !needExportCardResult.contains(cardInfo)) {
        needExportCardResult.add(cardInfo);
      }
    }
    return needExportCardResult;
  }

  static List<int> checkUserHuCard(List<int> userCards) {
    List<int> huCard = [];
    for (int cardId = 1; cardId <= 27; cardId++) {
      List<int> userCard = List.from(userCards);
      userCard.add(cardId);
      if (checkUserHu(userCard)) {
        huCard.add(cardId);
      }
    }
    return huCard;
  }

  static void removeCard(List<int> userCards, int exportCard) {
    int userCardSize = userCards.length;
    for (int i = userCardSize - 1; i >= 0; i--) {
      if (userCards[i] == exportCard) {
        userCards.removeAt(i);
        return;
      }
    }
  }

  static bool isHu(List<int> cardList) {
    return checkUserHu(cardList);
  }

  static Map<int, List<int>> cardByGroup(List<int> integers) {
    Map<int, List<int>> cardGroup = new Map<int, List<int>>();
    integers.forEach((val) {
      if (val >= 1 && val <= 9) {
        setCardGroupInfo(cardGroup, 0, val);
      } else if (val >= 10 && val <= 18) {
        setCardGroupInfo(cardGroup, 1, val);
      } else {
        setCardGroupInfo(cardGroup, 2, val);
      }
    });
    if (cardGroup[CARD_TYPE_WAN] == null) {
      cardGroup[CARD_TYPE_WAN] = [];
    }
    if (cardGroup[CARD_TYPE_TIAO] == null) {
      cardGroup[CARD_TYPE_TIAO] = [];
    }
    if (cardGroup[CARD_TYPE_TONG] == null) {
      cardGroup[CARD_TYPE_TONG] = [];
    }
    return cardGroup;
  }

  static void setCardGroupInfo(
      Map<int, List<int>> cardGroup, int type, int val) {
    if (cardGroup[type] == null) {
      cardGroup[type] = [val];
    } else {
      cardGroup[type].add(val);
    }
  }

  static List<int> checkCardNumber(List<int> userCard, int sum) {
    List<int> result = [];
    userCard.sort((a, b) {
      return a - b;
    });
    int temp;
    int tally = 0;
    for (int i = 0, j = userCard.length; i < j; i++) {
      int card = userCard[i];
      if (temp == null) {
        temp = card;
        tally++;
        continue;
      }
      if (tally >= sum && card == temp) {
        continue;
      } else if (card == temp) {
        tally++;
      } else {
        temp = card;
        tally = 1;
      }
      if (tally >= sum) {
        if (result.indexOf(temp) == -1) {
          result.add(temp);
        }
      }
    }

    return result;
  }

  static bool checkUserHu(List<int> userCardList) {
    int length = userCardList.length;
    if (length != 2 &&
        length != 5 &&
        length != 8 &&
        length != 11 &&
        length != 14) {
      return false;
    }
    Map<int, List<int>> cardGroup = cardByGroup(userCardList);
    bool result = false;
    //  0   1   2
    for (int index = 0; index < 3; index++) {
      if (result) {
        break;
      }
      Map<int, List<int>> tempCardGroup = new Map<int, List<int>>();
      tempCardGroup[CARD_TYPE_WAN] = List.from(cardGroup[CARD_TYPE_WAN]);
      tempCardGroup[CARD_TYPE_TIAO] = List.from(cardGroup[CARD_TYPE_TIAO]);
      tempCardGroup[CARD_TYPE_TONG] = List.from(cardGroup[CARD_TYPE_TONG]);
      tempCardGroup[CARD_TYPE_WAN].sort((a, b) {
        return a - b;
      });
      tempCardGroup[CARD_TYPE_TIAO].sort((a, b) {
        return a - b;
      });
      tempCardGroup[CARD_TYPE_TONG].sort((a, b) {
        return a - b;
      });
      //  分组
      int a = index + 1;
      int b = index + 2;
      int size = 3;
      if (a > size - 1) {
        a = a % 3;
      }
      if (b > size - 1) {
        b = b % 3;
      }
      bool aHu = true, bHu = true, cHu = true;
      if (tempCardGroup[index].length % 3 == 2 &&
          tempCardGroup[a].length % 3 == 0 &&
          tempCardGroup[b].length % 3 == 0) {
        // 第一种情况 判断  万条筒  3个牌型 是不是 只剩下2张
        if (tempCardGroup[index].length > 0) {
          aHu = checkPokerAabcd(tempCardGroup[index]);
        }
        if (tempCardGroup[a].length > 0) {
          bHu = checkPokerAabc(tempCardGroup[a]);
        }
        if (tempCardGroup[b].length > 0) {
          cHu = checkPokerAabc(tempCardGroup[b]);
        }
        result = aHu && bHu && cHu;
      } else if (userCardList.length == 14 &&
          tempCardGroup[index].length % 2 == 0 &&
          tempCardGroup[a].length % 2 == 0 &&
          tempCardGroup[b].length % 2 == 0) {
        if (tempCardGroup[index].length > 0) {
          aHu = checkPokerAA(tempCardGroup[index]);
        }
        if (tempCardGroup[a].length > 0) {
          bHu = checkPokerAA(tempCardGroup[a]);
        }
        if (tempCardGroup[b].length > 0) {
          cHu = checkPokerAA(tempCardGroup[b]);
        }
        // 第二种情况  判断  手牌 是不是 全都是对子
        result = aHu && bHu && cHu;
      }
    }
    return result;
  }

  static bool checkPokerAA(List<int> cardList) {
    if (cardList.length == 0) {
      return true;
    }
    if (cardList.length == 2) {
      if (cardList[0] == cardList[1]) {
        return true;
      } else {
        return false;
      }
    }
    bool flag;
    for (int start = cardList.length - 1; start > 1; start--) {
      var pokerOne = cardList[start];
      var pokerTwo = cardList[start - 1];
      // 找刻子
      if (pokerOne == pokerTwo) {
        cardList.removeAt(start);
        cardList.removeAt(start - 1);
        flag = checkPokerAA(cardList);
        if (flag) {
          return true;
        } else {
          cardList.insert(start - 1, pokerOne);
          cardList.insert(start, pokerOne);
          break;
        }
      }
    }
    return false;
  }

  static bool checkPokerAabc(List<int> cardList) {
    bool result = false;
    if (cardList == null || cardList.length == 0) {
      return true;
    }
    // 移除 3个相同的元素
    for (var i = 0, j = cardList.length - 2; i < j; i++) {
      var one = cardList[i];
      var two = cardList[i + 1];
      var three = cardList[i + 2];
      if (one == two && two == three) {
        cardList.removeAt(i);
        cardList.removeAt(i);
        cardList.removeAt(i);
        result = checkPokerAabc(cardList);
        if (result) {
          return true;
        } else {
          cardList.insert(i, one);
          cardList.insert(i, one);
          cardList.insert(i, one);
        }
      }
    }
    var temp = 0;
    for (var i = 0, j = cardList.length - 2; i < j; i++) {
      if (cardList[i] + 1 == cardList[i + 1]) {
        //在 1 跟 2 相等的情况下
        var index = i + 2;
        var size = cardList.length - 1;
        while (index <= size) {
          if (cardList[i + 1] + 1 == cardList[index]) {
            var a = cardList[i] + 1;
            var b = cardList[i];
            var c = cardList[index];
            cardList.removeAt(i);
            cardList.removeAt(i);
            cardList.removeAt(index - 2);
            result = checkPokerAabc(cardList);
            if (!result) {
              cardList.insert(i, a);
              cardList.insert(i, b);
              cardList.insert(index, c);
              i = temp++;
              break;
            } else {
              return true;
            }
          }
          index++;
        }
      }
    }
    return false;
  }

  static bool checkPokerAabcd(List<int> list) {
    if (list.length == 0) {
      return true;
    }
    if (list.length == 2) {
      if (list[0] == list[1]) {
        return true;
      } else {
        return false;
      }
    }
    bool flag;
    for (int start = list.length - 1; start > 1; start--) {
      int pokerOne = list[start];
      int pokerTwo = list[start - 1];
      int pokerThree = list[start - 2];
      // 找刻子
      if (pokerOne == pokerTwo && pokerTwo == pokerThree) {
        list.removeAt(start);
        list.removeAt(start - 1);
        list.removeAt(start - 2);
        flag = checkPokerAabcd(list);
        if (flag) {
          return true;
        } else {
          list.insert(start - 2, pokerOne);
          list.insert(start - 1, pokerOne);
          list.insert(start, pokerOne);
          break;
        }
      }
    }
    int temp = list.length - 1;
    // 找顺子的话 循环N-1次 [654321] 每后两个组合像前面找第一个不行就在往前面找一个
    for (int start = temp; start > 1; start--) {
      // 找顺子 123 判断相邻的两个值是否相等
      int pokerCard = list[start];
      int pokerCard2 = list[start - 1];
      if (pokerCard - 1 == pokerCard2) {
        // 找到第3个坐标
        int i = start - 2;
        while (i >= 0) {
          int pokerCard3 = list[i];
          // 判断第1,2是否相等
          if (pokerCard2 - 1 == pokerCard3) {
            list.removeAt(start);
            list.removeAt(start - 1);
            list.removeAt(i);
            flag = checkPokerAabcd(list);
            if (!flag) {
              list.insert(i, pokerCard3);
              list.insert(start - 1, pokerCard2);
              list.insert(start, pokerCard);
              start = temp--;
              break;
            } else {
              return true;
            }
          }
          i--;
        }
      }
    }
    return false;
  }
}
